package KademliaDht

import (
	"os"
//	"crypto/sha1"
	"hash/crc64"
	"bytes"
)

// Calculates the distance between two nodes.
// Kademlia algorithm uses XOR to calculate distances.
func Distance( id1 uint64, id2 uint64 ) uint64 {
	return id1 ^ id2
}

// Calculates the node that has distance X from other node.
func InvDistance( id1 uint64, dist uint64 ) uint64 {
	return id1 ^ dist
}

// Generate 64-bit key from a string
func GenerateKey( name string ) uint64 {
	h := crc64.New( crc64.MakeTable( crc64.ISO ) )
	buffer := bytes.NewBufferString( name )
	h.Write( buffer.Bytes() )
	return unMarshall_uint64( h.Sum()[0:2] )
}

func unMarshall_uint64(m []byte) uint64 {
	for len( m ) < 8 {
		n := make( []byte, 0, 0 )
		n = append( n, 0 )
		m = append( n, m... )
	}
	return uint64((uint64(m[0]) << 56)) + uint64((uint64(m[1]) << 48)) + uint64((uint64(m[2]) << 40)) + uint64((uint64(m[3]) << 32)) +
		uint64((uint64(m[4]) << 24)) + uint64((uint64(m[5]) << 16)) + uint64((uint64(m[6]) << 8)) + uint64(m[7])
}

type KademliaDht struct {
	node	*KadNode
}

func New_KademliaDht( ip string, k int, alpha int, bootstrap *KadContact ) ( kd *KademliaDht, error os.Error ) {
	node, error := New_KadNode_AutoId( ip, k, alpha, bootstrap )
	if error != nil {
		return nil, error
	}
	return &KademliaDht{ node }, nil
}

func ( kd *KademliaDht ) Put ( key uint64, value []byte ) {
	sh, _ := kd.node.Buckets.FindBucket( Distance( kd.node.MyContact.Id, key ) )
	nl := New_NodeLookup( kd.node, key, sh )
	nl.Find_Node()
	for _, c := range nl.Shortlist {
		c.Store( kd.node.MyContact, key, value )
	}
}

func ( kd *KademliaDht ) Get ( key uint64 ) ( value []byte, error os.Error ) {
	sh, _ := kd.node.Buckets.FindBucket( Distance( kd.node.MyContact.Id, key ) )
	nl := New_NodeLookup( kd.node, key, sh )
	value, error = nl.Find_Value()
	return value, error
}

func ( kd *KademliaDht ) Contact () *KadContact {
	return kd.node.MyContact
}


